package cg.server;

import cg.common.GameFinishedMessage;
import cg.common.UserAction;
import cg.common.UserMessage;
import cg.server.game.Spiel;
import cg.server.game.Spielstand;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import sun.io.Converters;

/**
 * Spielverwaltung
 *
 * @author Christian Friedli
 */
public class GameSession implements PlayerEventListener {

    Player[] _p;
    Spielstand _currentSnapshot;
    Spiel _spiel;

    public GameSession(Player p1, Player p2, Player p3, Player p4) {
        _p = new Player[4];
        _p[0] = p1;
        _p[1] = p2;
        _p[2] = p3;
        _p[3] = p4;
        _spiel = new Spiel();
        _spiel.GameMain(_p[0].getPlayerName(), _p[1].getPlayerName(), _p[2].getPlayerName(), _p[3].getPlayerName());
    }

    public void Init() {
        for (Player p : _p) {
            p.addEventListener(this);
        }
        _currentSnapshot = _spiel.GetSpielStand();
        SendOutSnapshot();
        SendOutObject(new UserMessage("Welcome to the Game", JOptionPane.INFORMATION_MESSAGE));
    }

    /**
     * Methode handlePlayerEvent nimmt die vom Spieler getätigten Events
     * entgegen und führ dementsprechend eine Aktion aus.
     *
     * @param PlayerEvent
     */
    @Override
    public void handlePlayerEvent(PlayerEvent event) {
        UserAction acc = (UserAction) event.getEventObject();
        Player p = (Player) event.getSource();

        System.out.println("Got Useraction from: " + p.getPlayerName() + " - " + acc.getMode() + " - " + acc.getParam());

        // von welchem Spieler kommt der eingegangen Event?
        int currentPlayer = 0;
        if (_p[0] == p) {
            currentPlayer = 1;
        } else if (_p[1] == p) {
            currentPlayer = 2;
        } else if (_p[2] == p) {
            currentPlayer = 3;
        } else if (_p[3] == p) {
            currentPlayer = 4;
        }

        if (Spiel.getAktuellerSpieler() != currentPlayer) {
            // Falls der Event von einem Spieler kommt, welcher nicht an der
            // Reihe ist, wird die Meldung folgende Meldung an den Client 
            // geschickt!
            try {
                p.SendObject(new UserMessage("Du bist nicht an der Reihe!", JOptionPane.ERROR_MESSAGE));
            } catch (IOException ex) {
                Logger.getLogger(GameSession.class.getName()).log(Level.SEVERE, null, ex);
            }
            SendOutObject(_spiel.GetSpielStand());
            return;
        }

        try {
            // Falls der Event vom aktuellen Spieler kommt, wird der 
            // entsprechende Event ausgelöst.
            if (acc.getMode() == UserAction.UserActionMode.ReiheAufnehmen) {
                // Wurde auf eine Reihekarte geklickt:
                // Falls zuvor eine Karte vom Stapel genommen wurde wird diese,
                // der angeklickten Reihe zu gewiesen!
                if (_spiel.getGezogeneKarte() != null) {
                    _spiel.karteAufReiheLegen(_spiel.getGezogeneKarte(), Integer.parseInt(acc.getParam()));
                } else {
                    // wurde zuvor keine Karte aufgenommen, wird die angeklickt 
                    // Reihe dem Spieler zugeteilt
                    _spiel.reiheAufnehmen(Integer.parseInt(acc.getParam()));
                    System.out.println(acc.getParam());
                }
            } else if (acc.getMode() == UserAction.UserActionMode.StapelKarte) {
                // Wurde auf den Kartenstapel gekickt, wird eine Karte vom
                // Stapel genommen.
                _spiel.karteAufnehmen();
            }
        } catch (InternalError ex) {
            try {
                p.SendObject(new UserMessage(ex.getMessage(), JOptionPane.ERROR_MESSAGE));
            } catch (IOException ex1) {
                Logger.getLogger(GameSession.class.getName()).log(Level.SEVERE, null, ex1);
            }
            // Nach jedem User-Event wird der neue Spielstand an die Clients 
            // gesendet.
            SendOutObject(_spiel.GetSpielStand());
            return;
        }

        SendOutObject(_spiel.GetSpielStand());
        GameFinishedMessage mes = _spiel.GetHighscore();
        if (mes != null) {
            SendOutObject(mes);
        }
    }

    /**
     * Methode um den Spielstand an den Client zu senden. Die Methode
     * unterscheidet ob der Client, welchem der Spielstand gesendet wird an der
     * Reihe ist oder nicht.
     */
    public void SendOutObject(Object o) {
        for (int i = 0; i < 4; i++) {
            try {
                if (o.getClass() == Spielstand.class) {
                    ((Spielstand) o).iAmPlayer = i + 1;
                }
                _p[i].SendObject(o);
            } catch (IOException ex) {
                Logger.getLogger(GameSession.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Methode um den aktuellen Spielstand an den Client zu senden
     */
    public void SendOutSnapshot() {
        SendOutObject(_currentSnapshot);
    }
}
